package com.example.basewarehouse.mvp;

import android.util.Log;

import com.example.basewarehouse.net.CallBackListener;
import com.example.basewarehouse.net.HttpException;
import com.example.basewarehouse.net.RetrofitApiService;
import com.example.basewarehouse.net.RetrofitUtils;
import com.example.basewarehouse.net.RetryWithDelay;
import com.example.basewarehouse.utils.TS;

import java.lang.ref.Reference;
import java.lang.ref.WeakReference;

import io.reactivex.Observable;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.disposables.Disposable;
import io.reactivex.functions.Consumer;
import io.reactivex.functions.Function;
import io.reactivex.schedulers.Schedulers;
import okhttp3.MediaType;
import okhttp3.RequestBody;

public class BasePresenter<V extends IView> implements IPresenter<IView> {
    // 此处使用弱引用是因为，有时Activity关闭不一定会走onDestroy，所以这时使用弱引用可以及时回收IView
    protected Reference<V> MvpRef;

    //这个是为了退出页面，取消请求的
    protected CompositeDisposable compositeDisposable;

    public BasePresenter(V view) {
        attachView(view);
    }

    private void attachView(V view) {
        MvpRef = new WeakReference<V>(view);
        compositeDisposable = new CompositeDisposable();
    }

    protected V getView() {
        if (MvpRef != null) {
            return MvpRef.get();
        }
        return null;
    }

    protected static RequestBody getRquestBody(String param) {
        return RequestBody.create(MediaType.parse("application/json; charset=utf-8"), param);
    }

    protected static RetrofitApiService getRetrofitApiService() {
        return RetrofitUtils.getRetrofitManager().getRetrofitApiService();
    }

    public <T> void networkRequest(Observable<BaseResponse<T>> observable, CallBackListener<T> callBackListener) {
        addDisposable(observable
                .subscribeOn(Schedulers.io())
                .doOnSubscribe(new Consumer<Disposable>() {
                    @Override
                    public void accept(Disposable disposable) throws Exception {
                        Log.d("Thread","doOnSubscribe当前线程"+Thread.currentThread().getName() );
                        if(callBackListener!=null){
                            callBackListener.onBeforeResponse();
                        }
                    }
                })
                .retryWhen(new RetryWithDelay(2,3000))//总共重试2次，重试间隔3000毫秒
                .map(new Function<BaseResponse<T>, T>() {
                    /**
                     * Apply some calculation to the input value and return some other value.
                     *
                     * @param tBaseResponse the input value
                     * @return the output value
                     * @throws Exception on error
                     */
                    @Override
                    public T apply(BaseResponse<T> tBaseResponse) throws Exception {
                        Log.d("Thread","map当前线程"+Thread.currentThread().getName() );
                        if(tBaseResponse.success()){
                            if(tBaseResponse.data!=null){
                                return tBaseResponse.data;
                            }else {
                                throw new HttpException(tBaseResponse.code,tBaseResponse.msg);
                            }
                        }else {
                            throw new HttpException(tBaseResponse.code,tBaseResponse.msg);
                        }
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Consumer<T>() {
                    @Override
                    public void accept(T t) throws Exception {
                        Log.d("Thread","subscribe当前线程"+Thread.currentThread().getName() );
                        if(callBackListener!=null){
                            callBackListener.onSucessData(200,"",t);
                        }
                    }
                }, new Consumer<Throwable>() {
                    @Override
                    public void accept(Throwable throwable) throws Exception {
                        Log.d("Thread","subscribe当前线程"+Thread.currentThread().getName() );
                        Log.d("Thread","throwable==="+throwable.getMessage() );
                        if(!isViewAttach()){
                            return;
                        }
                        try {
                            int status = ((HttpException)throwable).status;
                            String msg=((HttpException)throwable).msg;
                            if(status==200){
                                if(callBackListener!=null){
                                    callBackListener.onSucessData(status,"",null);
                                }
                            }else if(status==401){
                                if(callBackListener!=null){
                                    callBackListener.onLogin(status,msg);
                                }
                            }else {
                                TS.show(msg);
                                if(callBackListener!=null){
                                    callBackListener.onFailure(status,msg);
                                }
                            }
                        }catch (Exception e){
                            //返回了没有实体的数据
                            if(callBackListener!=null){
                                callBackListener.onSucessData(200,"",null);
                            }
                        }
                    }
                }));
    }

    /**
     * 主要用于判断IView的生命周期是否结束，防止出现内存泄露状况
     *
     * @return
     */
    protected boolean isViewAttach() {
        return MvpRef != null && MvpRef.get() != null;
    }


    /**
     * Activity生命周期结束时，Presenter也清除IView对象，不在持有
     */
    @Override
    public void detachView() {
        if (MvpRef != null) {
            MvpRef.clear();
            MvpRef = null;
        }
    }

    /**
     * 取消网络准备
     */

    public void addDisposable(Disposable disposable) {
        compositeDisposable.add(disposable);
    }

    public void removeDisposable() {
        if (compositeDisposable != null) {
            compositeDisposable.dispose();
        }
    }
}
